import State, { StateType } from "../common/state";
import { CompareState, Queue } from "../utils";
import { iteratorOnly, mapSetOnly } from '../utils/index'

class DFAState extends State {
    
    nfaStates: Set<State>
    
    readonly allId: string

    constructor(allId?: string, states?: Set<State>) {
        super()
        if(allId) {
            this.nfaStates = new Set(states)
            this.allId = allId
            for(let state of states) {
                if(state.isEndState) {
                    this._stateType = StateType.END
                }
            }
        }
        else {
            this.nfaStates = new Set()
        }
    }

    public nextState(edge: string): DFAState {
        return iteratorOnly(this.next.get(edge) as Set<DFAState>)
    }

    public toString(): string {
        return this.allId
    }

    public equals(other: DFAState): boolean {
        return this.allId === other.allId
    }
}

type DFAGroup = Array<DFAGroup>

class DFAGraph {
    private nfaStetes2dfaState: Map<string, DFAState>
    public start: DFAState
    constructor() {
        this.nfaStetes2dfaState = new Map()
        this.start = new DFAState()
    }
    
    public getOrBuild(states: Set<State>): DFAState {
        let allId = []
        for(let state of states) {
            allId.push(String(state.id))
        } 
        
        let allIdStr = allId.sort().join('#')
        if(!this.nfaStetes2dfaState.has(allIdStr)) {
            let dfaState = new DFAState(allIdStr, states)
            this.nfaStetes2dfaState.set(allIdStr, dfaState)
        }
        
        return this.nfaStetes2dfaState.get(allIdStr)
    }
    
    /**
     * *hopcroft*算法。用于化简dfa
     * @todo 针对字母表遍历我实在
     * # 无法接受，
     * 剩下的交给v8
     */
    public induct() {
        
    }

    public print() {
        console.log('>>>>>>>>>>>dfa<<<<<<<<<<')
        let que = new Queue<State>(),
            stateVis = new Set<State>()

        que.push(this.start)
        stateVis.add(this.start)
        while(!que.empty) {
            let curState = que.poll() as DFAState
            for(let entry of curState.next.entries()) {
                let edge = entry[0],
                    nextStates = entry[1] as Set<DFAState>
                for(let nextState of nextStates) {
                    console.log(`${curState.allId}(${curState.id}) -> ${nextState.allId}(${nextState.id}):  ${edge}`)
                    if(!stateVis.has(nextState)) {
                        que.push(nextState)
                        stateVis.add(nextState)
                    }
                }
            }
        }

        console.log('>>>>>>>>>>>end<<<<<<<<<<')
    }
}

/**
 * @template K,V
 * @param {Map<K, Set<V>>} map
 * @param {K} key 
 * @param {V} val 
 * 如果`set map`没有键`key`，则生成关系。
 * 否则在对应的`Set<V>`中插入`val`
 */
function setOrBuild<K = any, V = any>(map: Map<K, Set<V>>, key: K , val: V) {
    if(map.has(key)) 
        map.get(key).add(val)
    else
        map.set(key, new Set<V>().add(val))
}


export { DFAGraph, DFAState }